package memory.net;

import java.net.Socket;
import javax.swing.JOptionPane;

import memory.Card;
import memory.CardPanel;
import memory.Player;
import memory.PlayerPanel;


/* 
 * This class will listen and perform actions accordingly,
 * It will run on the client and will be started after 
 * connectivity has been established with the server.
 * 
 */


public class ClientThread implements Runnable {
	
	public Thread myThread = new Thread(this);
	private Socket mySocket;
	private NetEventListener netEventListener;
	private Player myPlayer;
		
	private Communicator communicate;
	private DebugWindow debugWindow;
	
	public ClientThread(Player p, Socket s, NetEventListener n, DebugWindow dW) {
		
		//Set inherent references
		myPlayer = p;
		mySocket = s;
		netEventListener = n;
		debugWindow = dW;
		
		//Add ourself to netEventListener so it know's where to send the clicks
		netEventListener.setClientThread(this);		
		
		//Initialize streams
		try {
			communicate = new Communicator(mySocket.getInputStream(), mySocket.getOutputStream());
			debugWindow.addMessage("Streams Initialized");
		}
		catch( Exception e ) {
			//Error, close thread
			JOptionPane.showMessageDialog(null, "ClientThread: Can't initialize streams!", "Error", JOptionPane.ERROR_MESSAGE);
			myThread.interrupt();
		}
			
		//Start thread
		myThread.start();
		
		
	}
	
	public void run() {
		
		try {
			
			while(!Thread.interrupted()) {
				
				//Recieve for 20ms then continue
				try {
					
					WrapperClass recieved = communicate.recieve();
					
					//Determine what to do with this nice peace of information
					try {
						takeAppropriateAction(recieved);
					}
					catch(Exception e ) {
						//Still don't know? package was malformed or wrongfully implemented. Can't 
						//garantera game integrety so disconnect
						break;
					}
										
				}
				catch(Exception e) {
					if(!mySocket.isConnected()) {
						mySocket.close();
					}
					//We recieved nothing so therefor do nothing.
				}
								
				//Try sending something if there's something to send
				communicate.sendFromQueue();
				
			}
		}
		catch(Exception e) {
			try {
				debugWindow.addMessage("Exception, exiting!");
				e.printStackTrace();
				mySocket.close();
			}
			catch(Exception e2) {}
		}
				
	}
	
	private void takeAppropriateAction(WrapperClass wC) throws Exception {
		
		//Inspect recieved package.
		debugWindow.addMessage("Taking action: command is " + wC.getContainingString());
		if(wC.getContainingObject() == null) {
			
			if(wC.getContainingString().indexOf("Begin Turn") != -1) {
				netEventListener.connectListeners();
			}
			else if(wC.getContainingString().indexOf("End Turn") != -1) {
				netEventListener.disconnectListeners();
			}
			else if(wC.getContainingString().indexOf("Error Hide All Cards") != -1) {
				netEventListener.hideAllCards();
			}
			else if(wC.getContainingString().indexOf("Player Name?") != -1) {
				debugWindow.addMessage("Sending my player.");
				communicate.addToQueue(new WrapperClass("My Player",(Player)myPlayer));
			}
			else if(wC.getContainingString().indexOf("Game Starting") != -1) {
				debugWindow.addMessage("Game is starting.");
				netEventListener.gameRunning(true);
			}
			
			
		}
		else if(wC.getContainingObject() instanceof Integer) {
			
			Integer id = (Integer)wC.getContainingObject();
			
			if(wC.getContainingString().indexOf("Show Card") != -1) {
				System.out.println("I'm showing the card with id " + id);
				netEventListener.showCard(id);
			}
			else if(wC.getContainingString().indexOf("Hide Card") != -1) {
				netEventListener.hideCard(id);
			}
			else if(wC.getContainingString().indexOf("Claimed Card") != -1) {
				netEventListener.claimCard(id);
			}
			//else if(wC.getContainingString().indexOf("New Card") != -1) {
			//	netEventListener.newCard(c);
			//}
			
		}
		else if(wC.getContainingObject() instanceof Player) {
			
			Player p = (Player)wC.getContainingObject();
			
			if(wC.getContainingString().indexOf("Next Player") != -1) {
				netEventListener.setCurrentPlayer(p);
			}
			else if(wC.getContainingString().indexOf("Updated Player") != -1) {
				netEventListener.updatePlayer(p);
			}
			else if(wC.getContainingString().indexOf("Disconnected Player") != -1) {
				netEventListener.disconnectedPlayer(p);
			}
			
		}
		else if(wC.getContainingObject() instanceof String) {
			
			if(wC.getContainingString().indexOf("Update Player List") != -1) {
				debugWindow.addMessage("Recieved a player name: " + (String)wC.getContainingObject());
				netEventListener.updatePlayerList((String)wC.getContainingObject());
			}
			else if(wC.getContainingString().indexOf("New Chat Message") != -1) {
				debugWindow.addMessage("Recieved a chat message");
				netEventListener.newChatMsg((String)wC.getContainingObject());
			}
			
		}		
		else if(wC.getContainingString().indexOf("New CardPanel") != -1 && wC.getContainingObject() instanceof CardPanel) {
			netEventListener.newCardPanel((CardPanel)wC.getContainingObject());
			debugWindow.addMessage("CardPanel recieved.");			
		}
		else if(wC.getContainingString().indexOf("New PlayerPanel") != -1 && wC.getContainingObject() instanceof PlayerPanel) {
			debugWindow.addMessage("PlayerPanel recieved");
			netEventListener.newPlayerPanel((PlayerPanel)wC.getContainingObject());
			if(netEventListener.amIReady()) {
				debugWindow.addMessage("Ready to play.");
				communicate.addToQueue(new WrapperClass("I'm ready",null));
			}
		}
		else {
			//Action not implemented, can't garantie game integrety
			debugWindow.addMessage("Action not implemented, disconnecting.");
			throw new Exception();
		}
		
	}
	
	public NetEventListener getNetEventListener() {
		return netEventListener;
	}
	
	public void leaveGame() {
		try {
			mySocket.close();
		}
		catch(Exception e) {}
	}
	
	public void addToQueue(WrapperClass wC) {
		communicate.addToQueue(wC);
	}
	
}